package org.ben.forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

public class ForkJoinTest {
    public static void main(String[] args) {
        //Integer.MAX_VALUE - 5;
        byte[] ba = new byte[Integer.MAX_VALUE/100 - 5];
        Random rd = new Random();
        int b1 = 0, b2 = 0;
        for(int i = 0 ; i < ba.length; i++) {
            if(rd.nextBoolean()) {
                b1++;
                ba[i] = 1;
            } else {
                b2++;
                ba[i] = 0;
            }
        }
      System.out.println("b1 = " + b1 + " ; b2 = " + b2);
//        List<Integer> result = new ArrayList<Integer>(ba.length/2);
//        long ctm = System.currentTimeMillis();
//        for(int i = 0; i < ba.length; i++) {
//            if(ba[i] == 1)
//                result.add(i);
//        }
//        System.out.println(result.size());
//        System.out.println(System.currentTimeMillis()-ctm);

        ForkJoinPool fkp = new ForkJoinPool();
        ForkTask task = new ForkTask(ba,0,ba.length);

        long ctm = System.currentTimeMillis();
        fkp.execute(task);

        while(!task.isDone());
        fkp.shutdown();
        try {
            fkp.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        long ctm1 = System.currentTimeMillis();
        try {
            System.out.println(task.get().size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("time costed = " + (ctm1 - ctm));
    }
}


class ForkTask extends RecursiveTask<List<Integer>> {
    private static final long serialVersionUID = -6297861255277486587L;
    private byte[] ba;
    private int startIndex;
    private int endIndex;
    private List<Integer> result = new ArrayList<Integer>(1000);

    ForkTask(byte[] b, int start, int end) {
        ba = b;
        startIndex = start;
        endIndex = end;
    }

    @Override
    protected List<Integer> compute() {
        if(endIndex - startIndex < 10000) {
//            System.out.println("start = " + startIndex + " end = " + endIndex);
            for(int i = startIndex; i < endIndex; i++) {
                if(ba[i] == 1)
                    result.add(i);
            }
//            System.out.println("Task end..." + result.size());
        } else {
            int middel = startIndex + (endIndex - startIndex) / 2;
            ForkTask task1 = new ForkTask(ba,startIndex,middel);
            ForkTask task2 = new ForkTask(ba,middel,endIndex);
            invokeAll(task1,task2);
            try {
                result = groupResults(task1.get(),task2.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    List<Integer> groupResults(List<Integer> r1, List<Integer> r2) {
//        System.out.println("r1.size = " + r1.size() + " r2.size = " + r2.size());
        r1.addAll(r2);
        return r1;
    }
}